/*
 *  uiView.cpp
 *  trail-map-editor
 *
 *  Created by Giorgio Tino on 2/18/13.
 *  Copyright 2013 __MyCompanyName__. All rights reserved.
 *
 */

#include "ui.h"

#define setObjectColor(o,pc,hc,a) if(hc){	sgVec3 color; \
											rgbaFromWebColor(color, hc); \
											o->setColor(pc, color[0], color[1], color[2], a); }

using namespace tinyxml2;

uiView::uiView(int x, int y, const float width, const float height) : puGroup(x, y)
{	
	this->width = width;
	this->height = height;
}

uiView::~uiView()
{
}

void uiView::setDelegate(uiViewDelegate* delegate)
{
    this->delegate = delegate;
}

// -------
// Factory
// -------

uiView* uiView::createView(const char* filename)
{
	if(!filename)
	{
		ulSetError(UL_FATAL, "NULL view file specified.",filename);
		return 0;
	}
    
    Log.write(PlainText, "Load view from file : %s", filename);
	
	XMLDocument doc;
	XMLError error = doc.LoadFile(filename);
	if(error)
	{
		ulSetError(UL_FATAL, "View file not found : %s.",filename);
		return 0;
	}
	
	//
	// Look for the 'scene' node.
	//
	XMLElement* viewElement = doc.FirstChildElement( "view" );
    
    if(!viewElement)
	{
		ulSetError ( UL_FATAL, "Cannot find view element in configuration %s. view must be the root element!", filename ) ;
		return 0;
	}
    
    return createView(viewElement);
}

uiView* uiView::createView(XMLElement* element)
{
    if(!element || !ulStrEqual(element->Name(),"view"))
    {
		ulSetError ( UL_WARNING, "Not a view element!" ) ;
		return 0;
	}
    
    float x = element->FloatAttribute("x");
    float y = element->FloatAttribute("y");
    float width = element->FloatAttribute("width");
    float height = element->FloatAttribute("height");
    
    // Open the puGroup!
    uiView* view = new uiView(x, y, width, height);
    
    //
    // Load the puObjects
    //
    parseElement(element->FirstChildElement(NULL), view, NULL); // Get the first one
    
    // Close the puGroup!
    view->close();
    
    return view;
}

void uiView::parseElement(const XMLElement* element, uiView* view, puObject* parent)
{
	const XMLElement* sibling = element;
	
	while(sibling)
	{
		puObject* object;
		
		bool shouldParseChildElements = beginElement(sibling, view, parent, &object);
		
		if(shouldParseChildElements) // Some elements parse the child elements on their own.
		{
			const XMLElement* child = sibling->FirstChildElement();
			
			if(child)
				parseElement(child, view, object);
		}
		
		endElement(sibling, view, parent, object);
		
		sibling = sibling->NextSiblingElement();
	}
}

bool uiView::beginElement(const XMLElement* element, uiView* view, puObject* parent, puObject** object)
{
	if(!element || !view)
		return false;
    
	//
	// False if we don't want the view to parse the child elements (e.g. the menu parses them on its own), True otherwise.
	//
	bool shouldParseChildElements = false;
	
    //
	// Common properties
	//
	float x = element->FloatAttribute("x");
	float y = element->FloatAttribute("y");
	float width = element->FloatAttribute("width");
	float height = element->FloatAttribute("height");
	
	bool enabled = element->Attribute("enabled") ? element->BoolAttribute("enabled") : true;
	bool hidden = element->Attribute("hidden") ? element->BoolAttribute("hidden") : false;
	
	const char* name = element->Attribute("name");
	const char* legend = element->Attribute("legend");
	const char* label = element->Attribute("label");
    
    int dirn = dirnFromString(element->Attribute("dirn"));
    int style = styleFromString(element->Attribute("style"));
    bool negative = element->Attribute("negative") ? element->BoolAttribute("negative") : false;
    int borderThickness = element->Attribute("borderThickness") ? element->IntAttribute("borderThickness") : -1;
	
	// PUCOL_*
	const char* foregroundColor = element->Attribute("foregroundColor");
	const char* backgroundColor = element->Attribute("backgroundColor");
	const char* highlightColor = element->Attribute("highlightColor");
	const char* labelColor = element->Attribute("labelColor");
	const char* legendColor = element->Attribute("legendColor");
	const char* miscColor = element->Attribute("miscColor");
	
	// PUPLACE_*
	int labelPlace = element->Attribute("labelPlace") ? placeFromString(element->Attribute("labelPlace")) : PUPLACE_BOTTOM_RIGHT;
	int legendPlace = element->Attribute("legendPlace") ? placeFromString(element->Attribute("legendPlace")) : PUPLACE_CENTERED_CENTERED;
	
	sgFloat alpha = element->Attribute("alpha") ? element->FloatAttribute("alpha") : 1.0f;
	
	//
	// Callback related stuff:
	//		scene : the scene target, where we handle the callbacks.
	//		name  : the object name, in order to understand which object fired the event.
	//
	uiData* data = new uiData(name, view);
	puObject* newObject = NULL;
    
	//
	// Specific properties and object creation
	//
	if(XMLUtil::StringEqual( element->Name(), "group" ))
	{
		bool floating = element->Attribute("floating") ? element->BoolAttribute("floating") : false;
		
		uiGroup *group = new uiGroup(x,y);
        //		group->setSize(width, height);
		group->setFloating(floating);
		
		newObject = group;
		
		shouldParseChildElements = true;
	}
	else if(XMLUtil::StringEqual( element->Name(), "button" ))
	{
		puObject* button = NULL;
		const char* normalImage = element->Attribute("normalImage");
		const char* clickedImage = element->Attribute("clickedImage");
		const char* focusedImage = element->Attribute("focusedImage");
		const char* disabledImage = element->Attribute("disabledImage");
		
		if(normalImage && clickedImage && focusedImage && disabledImage)
		{
			button = new uiButton(x, y, x+width, y+height, normalImage, focusedImage, clickedImage, disabledImage);
		}
		else
		{
			button = new puButton(x, y, x+width, y+height);
		}
		
		newObject = button;
	}
	else if(XMLUtil::StringEqual( element->Name(), "arrowbutton" ))
	{
		int arrowType = arrowTypeFromString(element->Attribute("arrowType"));
		uiArrowButton* arrowButton = new uiArrowButton(x,y,x+width,y+height,arrowType);
		
		newObject = arrowButton;
	}
	else if(XMLUtil::StringEqual( element->Name(), "oneshot" ))
	{
		uiOneShot* oneShot = new uiOneShot(x,y,x+width,y+height);
		
		newObject = oneShot;
	}
	else if(XMLUtil::StringEqual( element->Name(), "slider" ))
	{
		float size = element->Attribute("orientation") ? element->FloatAttribute("size") : width;
		bool isVertical = element->Attribute("orientation") ? XMLUtil::StringEqual( element->Attribute("orientation"), "vertical" ) : false;
		float minValue = element->Attribute("minValue") ? element->FloatAttribute("minValue") : 0.0f;
		float maxValue = element->Attribute("maxValue") ? element->FloatAttribute("maxValue") : 1.0f;
		float stepSize = element->Attribute("stepSize") ? element->FloatAttribute("stepSize") : 0.0f;
		float value = element->Attribute("value") ? element->FloatAttribute("value") : minValue;
		float sliderFraction = element->Attribute("sliderFraction") ? element->FloatAttribute("sliderFraction") : 0.1f;
		int mode = sliderModeFromString(element->Attribute("mode"));
		float delta = element->Attribute("delta") ? element->FloatAttribute("delta") : 0.0f;
        
		uiSlider* slider = new uiSlider(x, y, size, isVertical, height);
		slider->setMinValue(minValue);
		slider->setMaxValue(maxValue);
		slider->setStepSize(stepSize);
		slider->setValue(value);
		slider->setSliderFraction(sliderFraction);
		slider->setCBMode(mode);
		
		if(mode == PUSLIDER_DELTA)
			slider->setDelta(delta);
		
		newObject = slider;
	}
	else if(XMLUtil::StringEqual( element->Name(), "bislider" ))
	{
		float size = element->Attribute("orientation") ? element->FloatAttribute("size") : width;
		bool isVertical = element->Attribute("orientation") ? XMLUtil::StringEqual( element->Attribute("orientation"), "vertical" ) : false;
		float minValue = element->Attribute("minValue") ? element->FloatAttribute("minValue") : 0.0f;
		float maxValue = element->Attribute("maxValue") ? element->FloatAttribute("maxValue") : 1.0f;
		float stepSize = element->Attribute("stepSize") ? element->FloatAttribute("stepSize") : 0.0f;
		float currentMin = element->Attribute("currentMin") ? element->FloatAttribute("currentMin") : minValue;
		float currentMax = element->Attribute("currentMax") ? element->FloatAttribute("currentMax") : maxValue;
		float sliderFraction = element->Attribute("sliderFraction") ? element->FloatAttribute("sliderFraction") : 0.1f;
		int mode = sliderModeFromString(element->Attribute("mode"));
		float delta = element->Attribute("delta") ? element->FloatAttribute("delta") : 0.0f;
		
		uiBiSlider* biSlider = new uiBiSlider(x, y, size, isVertical);
		biSlider->setMinValue(minValue);
		biSlider->setMaxValue(maxValue);
		biSlider->setStepSize(stepSize);
		biSlider->setCurrentMin(currentMin);
		biSlider->setCurrentMax(currentMax);
		biSlider->setSliderFraction(sliderFraction);
		biSlider->setCBMode(mode);
		
		if(mode == PUSLIDER_DELTA)
			biSlider->setDelta(delta);
		
		newObject = biSlider;
	}
	else if(XMLUtil::StringEqual( element->Name(), "trislider" ))
	{
		float size = element->Attribute("orientation") ? element->FloatAttribute("size") : width;
		bool isVertical = element->Attribute("orientation") ? XMLUtil::StringEqual( element->Attribute("orientation"), "vertical" ) : false;
		float minValue = element->Attribute("minValue") ? element->FloatAttribute("minValue") : 0.0f;
		float maxValue = element->Attribute("maxValue") ? element->FloatAttribute("maxValue") : 1.0f;
		float stepSize = element->Attribute("stepSize") ? element->FloatAttribute("stepSize") : 0.0f;
		float currentMin = element->Attribute("currentMin") ? element->FloatAttribute("currentMin") : minValue;
		float value = element->Attribute("value") ? element->FloatAttribute("value") : minValue;
		float currentMax = element->Attribute("currentMax") ? element->FloatAttribute("currentMax") : maxValue;
		float sliderFraction = element->Attribute("sliderFraction") ? element->FloatAttribute("sliderFraction") : 0.1f;
		int mode = sliderModeFromString(element->Attribute("mode"));
		float delta = element->Attribute("delta") ? element->FloatAttribute("delta") : 0.0f;
		bool freezeEnds = element->Attribute("freezeEnds") ? element->Attribute("freezeEnds") : false;
		
		uiTriSlider* triSlider = new uiTriSlider(x, y, size, isVertical);
		triSlider->setMinValue(minValue);
		triSlider->setMaxValue(maxValue);
		triSlider->setStepSize(stepSize);
		triSlider->setCurrentMin(currentMin);
		triSlider->setValue(value);
		triSlider->setCurrentMax(currentMax);
		triSlider->setSliderFraction(sliderFraction);
		triSlider->setFreezeEnds(freezeEnds);
		triSlider->setCBMode(mode);
		
		if(mode == PUSLIDER_DELTA)
			triSlider->setDelta(delta);
		
		newObject = triSlider;
	}
	else if(XMLUtil::StringEqual( element->Name(), "dial" ))
	{
		float size = element->Attribute("size") ? element->FloatAttribute("size") : width;
		float minValue = element->Attribute("minValue") ? element->FloatAttribute("minValue") : 0.0f;
		float maxValue = element->Attribute("maxValue") ? element->FloatAttribute("maxValue") : 1.0f;
		float stepSize = element->Attribute("stepSize") ? element->FloatAttribute("stepSize") : 0.0f;
		float value = element->Attribute("value") ? element->FloatAttribute("value") : minValue;
		int mode = sliderModeFromString(element->Attribute("mode"));
		float delta = element->Attribute("delta") ? element->FloatAttribute("delta") : 0.0f;
		bool wrap = element->Attribute("wrap") ? element->BoolAttribute("wrap") : true;
		
		uiDial* dial = new uiDial(x, y, size);
		dial->setMinValue(minValue);
		dial->setMaxValue(maxValue);
		dial->setStepSize(stepSize);
		dial->setValue(value);
		dial->setWrap(wrap);
		dial->setCBMode(mode);
		
		if(mode == PUSLIDER_DELTA)
			dial->setDelta(delta);
		
		newObject = dial;
	}
	else if(XMLUtil::StringEqual( element->Name(), "frame" ))
	{
		uiFrame* frame = new uiFrame(x,y,x+width,y+height);
		
		newObject = frame;
	}
	else if(XMLUtil::StringEqual( element->Name(), "text" ))
	{
		uiText* text = new uiText(x,y);
		
		newObject = text;
	}
	else if(XMLUtil::StringEqual( element->Name(), "input" ))
	{
		bool inputEnabled = element->Attribute("inputEnabled") ? element->BoolAttribute("inputEnabled") : true;
		const char* validData = element->Attribute("validData");
		
		uiInput* input = new uiInput(x,y,x+width,y+height);
		
		if(inputEnabled)
			input->enableInput();
		else
			input->disableInput();
		
		if(validData)
			input->setValidData(validData);
		
		newObject = input;
	}
	else if(XMLUtil::StringEqual( element->Name(), "largeinput" ))
	{
		int arrows = arrowsFromString(element->Attribute("arrows"));
		int slidersWidth = element->Attribute("slidersWidth") ? element->IntAttribute("slidersWidth") : 10;
		bool wrapText = element->Attribute("wrapText") ? element->BoolAttribute("wrapText") : false;
		bool inputEnabled = element->Attribute("inputEnabled") ? element->BoolAttribute("inputEnabled") : true;
		const char* validData = element->Attribute("validData");
		
		uiLargeInput* largeInput = new uiLargeInput(x,y,width,height,arrows,slidersWidth,wrapText);
		
		if(inputEnabled)
			largeInput->enableInput();
		else
			largeInput->disableInput();
		
		if(validData)
			largeInput->setValidData(validData);
		
		newObject = largeInput;
	}
    else if(XMLUtil::StringEqual( element->Name(), "popup" ))
	{
        bool floating = element->Attribute("floating") ? element->BoolAttribute("floating") : false;
        
		uiPopup* popup = new uiPopup(x,y);
		popup->setFloating(floating);
        
		newObject = popup;
		
		shouldParseChildElements = true;
	}
    else if(XMLUtil::StringEqual( element->Name(), "dialogbox" ))
	{
        bool floating = element->Attribute("floating") ? element->BoolAttribute("floating") : false;
        
		uiDialogBox* dialogBox = new uiDialogBox(x,y);
		dialogBox->setFloating(floating);
        
		newObject = dialogBox;
	}
    else if(XMLUtil::StringEqual( element->Name(), "popupmenu" ))
	{
        bool floating = element->Attribute("floating") ? element->BoolAttribute("floating") : false;
        
		uiPopupMenu* popupMenu = new uiPopupMenu(x,y);
		popupMenu->setFloating(floating);
        
		newObject = popupMenu;
		
		shouldParseChildElements = true;
	}
    else if(XMLUtil::StringEqual( element->Name(), "popupmenuitem" ))
    {
        if(parent && (parent->getType() & PUCLASS_POPUPMENU))
        {
            const char* text = ulStrDup(element->Attribute("text"));
            
            uiPopupMenu* popupMenu = (uiPopupMenu*)parent; // Yes, this HAS to be correct
            
            puOneShot* item = (puOneShot*)popupMenu->add_item(text, NULL); // A call back will be set anyway later, along with user data
            
            newObject = item;
        }
    }
    else if(XMLUtil::StringEqual( element->Name(), "menubar" ))
    {
		int h = element->Attribute("height") ? element->IntAttribute("height") : -1;
		
		uiMenuBar* menuBar = new uiMenuBar(h);
		
        newObject = menuBar;
    }
	else if(XMLUtil::StringEqual( element->Name(), "verticalmenu" ))
    {
		int menuX = element->Attribute("x") ? element->IntAttribute("x") : -1;
		int menuY = element->Attribute("y") ? element->IntAttribute("y") : -1;
		
		uiVerticalMenu* verticalMenu = new uiVerticalMenu(menuX, menuY);
		
        newObject = verticalMenu;
    }
    else if(XMLUtil::StringEqual( element->Name(), "listbox" ))
    {
        uiListBox* listBox = new uiListBox(x, y, x+width, y+height, NULL); // NOTE : no list yet
        
        newObject = listBox;
    }
    else if(XMLUtil::StringEqual( element->Name(), "buttonbox" ))
    {
        bool oneButton = element->Attribute("oneButton") ? element->BoolAttribute("oneButton") : false;
        
        uiButtonBox* buttonBox = new uiButtonBox(x, y, x+width, y+height, NULL, oneButton); // NOTE : no list yet
        
        newObject = buttonBox;
    }
    else if(XMLUtil::StringEqual( element->Name(), "combobox" ))
    {
        bool editable = element->Attribute("editable") ? element->BoolAttribute("editable") : false;
        
        uiComboBox* comboBox = new uiComboBox(x, y, x+width, y+height, NULL, editable); // NOTE : no list yet
        
        newObject = comboBox;
    }
    else if(XMLUtil::StringEqual( element->Name(), "selectbox" ))
    {        
        uiSelectBox* selectBox = new uiSelectBox(x, y, x+width, y+height, NULL); // NOTE : no list yet
        
        newObject = selectBox;
    }
    else if(XMLUtil::StringEqual( element->Name(), "fileselector" ))
    {
        int arrows = arrowsFromString(element->Attribute("arrows"));
        const char* dir = ulStrDup(element->Attribute("dir"));
        const char* title = ulStrDup(element->Attribute("title"));
        
        uiFileSelector* fileSelector = new uiFileSelector(x, y, width, height, arrows, dir, title); // NOTE : no list yet
        
        newObject = fileSelector;
    }
	
    if(newObject && (newObject != parent))
    {
        //
        // Common setters
        //
        if(legend) 
		{
			newObject->setLegend(ulStrDup(legend));
			newObject->setLegendPlace(legendPlace);
		}
        if(label) 
		{
			newObject->setLabel(ulStrDup(label));
			newObject->setLabelPlace(labelPlace);
		}
		
        if(!enabled) newObject->greyOut();
        if(hidden) newObject->hide();
        if(data) newObject->setUserData(data);
        
        newObject->setActiveDirn(dirn);
        newObject->setStyle(negative ? style : -style);
        if(borderThickness >= 0) newObject->setBorderThickness(borderThickness); // after the style, or will be overwritten
		      
		setObjectColor(newObject,PUCOL_FOREGROUND,foregroundColor,alpha);
		setObjectColor(newObject,PUCOL_BACKGROUND,backgroundColor,alpha);
		setObjectColor(newObject,PUCOL_HIGHLIGHT,highlightColor,alpha);
		setObjectColor(newObject,PUCOL_LEGEND,legendColor,alpha);
		setObjectColor(newObject,PUCOL_LABEL,labelColor,alpha);
		setObjectColor(newObject,PUCOL_MISC,miscColor,alpha);
        
        // callbacks
        newObject->setCallback(_ui_cb);
        newObject->setActiveCallback(_ui_active_cb);
        newObject->setDownCallback(_ui_down_cb);
    }
	
	// Set the out param
	*object = newObject;
	
	return shouldParseChildElements;
}

void uiView::endElement(const XMLElement* element, uiView* view, puObject* parent, puObject* object)
{
	if(!element)
		return;
	
	if(XMLUtil::StringEqual( element->Name(), "group" ))
	{
		uiGroup* group = (uiGroup*)object;
		
		group->close();
	}
    else if(XMLUtil::StringEqual( element->Name(), "popup" ))
	{
		uiPopup* popup = (uiPopup*)object;
		
		popup->close();
	}
    else if(XMLUtil::StringEqual( element->Name(), "dialogbox" ))
	{
		uiDialogBox* dialogBox = (uiDialogBox*)object;
		
		dialogBox->close();
	}
    else if(XMLUtil::StringEqual( element->Name(), "popupmenu" ))
	{
		uiPopupMenu* popupMenu = (uiPopupMenu*)object;
		
		popupMenu->close();
	}
    else if(XMLUtil::StringEqual( element->Name(), "menubar" ))
	{
		uiMenuBar* menuBar = (uiMenuBar*)object;
		
		menuBar->load(element);
		
		menuBar->close();
	}
	else if(XMLUtil::StringEqual( element->Name(), "verticalmenu" ))
	{
		uiVerticalMenu* verticalMenu = (uiVerticalMenu*)object;
		
		verticalMenu->load(element);
		
		verticalMenu->close();
	}
    else if(XMLUtil::StringEqual( element->Name(), "listbox" ))
    {
        uiListBox* listBox = (uiListBox*)object;
        
        listBox->load(element);
    }
    else if(XMLUtil::StringEqual( element->Name(), "buttonbox" ))
    {
        uiButtonBox* buttonBox = (uiButtonBox*)object;
        
        buttonBox->load(element);
    }
    else if(XMLUtil::StringEqual( element->Name(), "combobox" ))
    {
        uiComboBox* comboBox = (uiComboBox*)object;
        
        comboBox->load(element);
    }
    else if(XMLUtil::StringEqual( element->Name(), "selectbox" ))
    {
        uiSelectBox* selectBox = (uiSelectBox*)object;
        
        selectBox->load(element);
    }
}

int uiView::dirnFromString(const char* dirn)
{
    //static const char *file_submenu   [] = { "up", "down", "continual", "updown", NULL};
    if(ulStrEqual(dirn,"up"))
       return PU_UP;
    else if(ulStrEqual(dirn,"down"))
        return PU_DOWN;
    else if(ulStrEqual(dirn,"continual"))
        return PU_CONTINUAL;
    else if(ulStrEqual(dirn,"updown"))
        return PU_UP_AND_DOWN;
    else
        return PU_UP;
}

int uiView::styleFromString(const char* style)
{    
    if(ulStrEqual(style,"none"))
        return PUSTYLE_NONE;
    else if(ulStrEqual(style,"plain"))
        return PUSTYLE_PLAIN;
    else if(ulStrEqual(style,"shaded"))
        return PUSTYLE_SHADED;
    else if(ulStrEqual(style,"small-shaded"))
        return PUSTYLE_SMALL_SHADED;
    else if(ulStrEqual(style,"bevelled"))
        return PUSTYLE_BEVELLED;
    else if(ulStrEqual(style,"small-bevelled"))
        return PUSTYLE_SMALL_BEVELLED;
    else if(ulStrEqual(style,"boxed"))
        return PUSTYLE_BOXED;
    else if(ulStrEqual(style,"special-underlined"))
        return PUSTYLE_SPECIAL_UNDERLINED;
    else if(ulStrEqual(style,"dropshadow"))
        return PUSTYLE_DROPSHADOW;
    else if(ulStrEqual(style,"radio"))
        return PUSTYLE_RADIO;
    else
        return PUSTYLE_SHADED;
}

int uiView::arrowTypeFromString(const char* arrowType)
{    
    if(ulStrEqual(arrowType,"up"))
        return PUARROW_UP;
    else if(ulStrEqual(arrowType,"down"))
        return PUARROW_DOWN;
    else if(ulStrEqual(arrowType,"left"))
        return PUARROW_LEFT;
    else if(ulStrEqual(arrowType,"right"))
        return PUARROW_RIGHT;
    else if(ulStrEqual(arrowType,"fast-up"))
        return PUARROW_FASTUP;
    else if(ulStrEqual(arrowType,"fast-down"))
        return PUARROW_FASTDOWN;
    else if(ulStrEqual(arrowType,"fast-left"))
        return PUARROW_FASTLEFT;
    else if(ulStrEqual(arrowType,"fast-right"))
        return PUARROW_FASTRIGHT;
    else
        return PUARROW_RIGHT;
}

void uiView::rgbaFromWebColor(sgVec3 color, const char* sWebColor)
{
	if(!sWebColor || (strlen(sWebColor) != 7)) // #123456
	{
		sgSetVec3(color,0,0,0);
		return;
	}
	
	char hexString[7];
	sscanf(sWebColor,"#%s",hexString);
	unsigned long webColor = strtoul(hexString, NULL, 16);
	
	sgFloat red = (sgFloat)((webColor >> 16) & 0x000000ffL) / 255.0f;
	
	sgFloat green = (sgFloat)((webColor >> 8) & 0x000000ffL) / 255.0f;
	
	sgFloat blue = (sgFloat)(webColor & 0x000000ffL) / 255.0f;
	
	sgSetVec3(color, red, green, blue);
}

int uiView::placeFromString(const char* place)
{    
    if(ulStrEqual(place,"above-left"))
        return PUPLACE_ABOVE_LEFT;
    else if(ulStrEqual(place,"above-right"))
        return PUPLACE_ABOVE_RIGHT;
    else if(ulStrEqual(place,"top-left"))
        return PUPLACE_TOP_LEFT;
    else if(ulStrEqual(place,"top-centered"))
        return PUPLACE_TOP_CENTERED;
    else if(ulStrEqual(place,"top-right"))
        return PUPLACE_TOP_RIGHT;
    else if(ulStrEqual(place,"upper-left"))
        return PUPLACE_UPPER_LEFT;
    else if(ulStrEqual(place,"upper-right"))
        return PUPLACE_UPPER_RIGHT;
    else if(ulStrEqual(place,"centered-left"))
        return PUPLACE_CENTERED_LEFT;
	else if(ulStrEqual(place,"centered-centered"))
        return PUPLACE_CENTERED_CENTERED;
	else if(ulStrEqual(place,"centered-right"))
        return PUPLACE_CENTERED_RIGHT;
	else if(ulStrEqual(place,"lower-left"))
        return PUPLACE_LOWER_LEFT;
	else if(ulStrEqual(place,"lower-right"))
        return PUPLACE_LOWER_RIGHT;
	else if(ulStrEqual(place,"bottom-left"))
        return PUPLACE_BOTTOM_LEFT;
    else if(ulStrEqual(place,"bottom-centered"))
        return PUPLACE_BOTTOM_CENTERED;
    else if(ulStrEqual(place,"bottom-right"))
        return PUPLACE_BOTTOM_RIGHT;
	else if(ulStrEqual(place,"below-left"))
        return PUPLACE_BELOW_LEFT;
    else if(ulStrEqual(place,"below-right"))
        return PUPLACE_BELOW_RIGHT;
    else
        return PUPLACE_LOWER_RIGHT;
}

int uiView::sliderModeFromString(const char* mode)
{    
	if(ulStrEqual(mode,"click"))
        return PUSLIDER_CLICK;
	else if(ulStrEqual(mode,"delta"))
        return PUSLIDER_DELTA;
    else if(ulStrEqual(mode,"always"))
        return PUSLIDER_ALWAYS;
    else
        return PUSLIDER_ALWAYS;
}

int uiView::arrowsFromString(const char* arrows)
{    
	if(ulStrEqual(arrows,"none"))
        return 0;
	else if(ulStrEqual(arrows,"single"))
        return 1;
    else if(ulStrEqual(arrows,"double"))
        return 2;
    else
        return 1;
}

// ---------------
// Virtual Methods
// ---------------
void uiView::display(void)
{

}

void uiView::resize(int w, int h)
{
}

void uiView::keyUp(unsigned char key, int x, int y)
{
	
}

void uiView::keyDown(unsigned char key, int x, int y)
{
	
}

void uiView::specialUp(int key, int x, int y)
{
	
}

void uiView::specialDown(int key, int x, int y)
{
	
}

void uiView::motion(int newx, int newy)
{
}

void uiView::passive(int newx, int newy)
{
	
}

void uiView::mouse(int button, int updown, int x, int y)
{

}

const puObject* uiView::findByName(const char* name) const
{
	return uiFindByName(this, name);
}

// ---------
// Callbacks
// ---------
uiData* uiView::_get_data(puObject* object)
{
	uiData* data = (uiData*)object->getUserData();
	
	if(!data)
	{
		ulSetError(UL_WARNING, "No callback data set for puObject callback!");
		return 0;
	}
	else if(!data->view)
	{
		ulSetError(UL_WARNING, "No view target set for puObject callback!");
		return 0;
	}
	
	return data;
}

void uiView::_ui_cb(puObject* object)
{
	uiData* data = _get_data(object);
	
	if(!data)
		return;
	
    if(data->view)
    {
        const char* name = data ? data->name : "";
        uiView* view = data->view;
        if(view->delegate)
        {
            view->delegate->onCallback(view, name, object);
        }
    }
}

void uiView::_ui_active_cb(puObject* object)
{
	uiData* data = _get_data(object);
	
	if(!data)
		return;
	
    if(data->view)
    {
        const char* name = data ? data->name : "";
        uiView* view = data->view;
        if(view->delegate)
        {
            view->delegate->onActiveCallback(view, name, object);
        }
    }
}

void uiView::_ui_down_cb(puObject* object)
{
	uiData* data = _get_data(object);
	
	if(!data)
		return;
	
    if(data->view)
    {
        const char* name = data ? data->name : "";
        uiView* view = data->view;
        if(view->delegate)
        {
            view->delegate->onDownCallback(view, name, object);
        }
    }
}